#include "APP_Diag.h"

#define DIAG_FUN_CAL_INTER_TIME     (100)       //诊断函数调用间隔 100ms

#define DIAG_OVER_CURR              (200)       //过流
#define DIAG_OVER_CURR_DLY          (5000)      //过流延时
#define DIAG_OVER_LOAD              (4000)      //过载电流35.00
#define DIAG_OVER_LOAD_DLY          (5000)      //过载电流延时5S


#pragma pack(1)
typedef struct{
    uint8_t over_volt       :1; //过压
    uint8_t under_volt      :1; //欠压
    uint8_t over_curr       :1; //过流
    uint8_t over_load       :1; //过载
    uint8_t shor_circ       :1; //短路
    uint8_t ground_wire     :1; //接地异常
    uint8_t relay_adhesion  :1; //继电器黏连
    uint8_t leakage_curr    :1; //漏电流故障
    uint8_t over_temper1    :1;
    uint8_t over_temper2    :1;  
}diag_sig_st;
#pragma pack()

typedef union{
    diag_sig_st signal;
    uint8_t diag_array[10];
}diag_type_st;
diag_type_st diag_sta;

/*******************************************************************************
* Function Name  : 
* Description    : 
* Input          : 
* Output         : None
* Return         : None
*******************************************************************************/
uint8_t diag_get_st(void)
{
    uint8_t i;
    
    diag_sta.signal.over_temper1=0;
    
    for(i=0; i<10; i++)
    {
        if(diag_sta.diag_array[i])
        {
            return 1;
        }
    }
    
    return 0;
}


/*******************************************************************************
* Function Name  : cal_leakage_curr
* Description    : 漏电流校准
* Input          : 
* Output         : None
* Return         : None
  漏电流校准需要在每次上电时进行
*******************************************************************************/
uint8_t cal_leakage_curr(void)
{
    vTaskDelay(100);
    rcd_cal_set(0);
    vTaskDelay(80);     /* 必须大于50ms */
    rcd_cal_set(1);
    vTaskDelay(80);
    
    return 1;
}

/*******************************************************************************
* Function Name  : RCD_SlefTest
* Description    : 漏电流自检
* Input          : 
* Output         : None
* Return         : None
  模拟漏电流
*******************************************************************************/
uint8_t RCD_SlefTest(void)
{
    uint8_t val=0;
    
    rcd_test_set(1);
    vTaskDelay(500);
    val = rcd_trip_read();
    
    return val;
}


/*******************************************************************************
* Function Name  : diag_groud_wire
* Description    : 接地检测
* Input          : 
* Output         : None
* Return         : 1-接地异常, 0-接地正常
*******************************************************************************/
uint8_t diag_groud_wire(void)
{
    if( le_read() && ne_read() )
    {
        diag_sta.signal.ground_wire=1;
    }
    else
    {
        diag_sta.signal.ground_wire=0;
    }
    
    return diag_sta.signal.ground_wire;
}


/*******************************************************************************
* Function Name  : realy_adhesion_check
* Description    : 继电器黏连检测
* Input          : None
* Output         : None
* Return         : 1-继电器黏连, 0-继电器正常
1.做继电器黏连检测时必须先断开交流继电器
*******************************************************************************/
uint8_t realy_adhesion_check(void)
{
    ac_relay_set(0);    /* 断开交流继电器 */
    vTaskDelay(10);
    if( (0==k1_fault_read()) || (0==k2_fault_read()) )
    {
        /* k1,k2任意一个引脚检测到低电平时, 继电器黏连 */  
        diag_sta.signal.relay_adhesion=1;
    }
    else
    {
        diag_sta.signal.relay_adhesion=0;
    }
    
    return diag_sta.signal.relay_adhesion;
}

/*******************************************************************************
* Function Name  : short_circuit_check
* Description    : 短路检测
* Input          : None
* Output         : None
* Return         : 1-异常, 0-正常
1.短路检测在每次闭合主继电器时进行
*******************************************************************************/
uint8_t short_circuit_check(void)
{
    uint16_t val=0;
    
    ac_relay_set(0);
    vTaskDelay(1);
    short_circuit_set(1);
    vTaskDelay(5);
    //short_circuit_adc_get(&val);
    
    if(val>50) //??
    {
        diag_sta.signal.shor_circ=1;
    }
    else
    {
        diag_sta.signal.shor_circ=0;
    }
    
    return diag_sta.signal.shor_circ;
}



/*******************************************************************************
* Function Name  : diag_overcurr
* Description    : 过流
* Input          : 
* Output         : None
* Return         : None
1.PWM电流≤20A,  且实际工作电流超过PWM电流+2A并持续5S
2.PWM电流＞20A，且实际工作电流超过PWM电流1.1倍并持续5S
*******************************************************************************/
static uint8_t diag_overcurr(void)
{
    uint16_t cp_duty;
     int16_t curr_max,curr;
    uint16_t dly=0;
    
    cp_duty_get(&cp_duty);
    curr_max = cp_duty_to_curr(cp_duty);
//    curr = meter.Curr;
    if(curr_max<=2000)
    {
        if( (curr+DIAG_OVER_CURR) >= curr_max)
        {
            if(++dly>=DIAG_OVER_CURR_DLY)
            {
                dly=DIAG_OVER_CURR_DLY;
                diag_sta.signal.over_curr=1;
            }
        }
        else
        {
            dly=0;
            diag_sta.signal.over_curr=0;
        }
    }
    else
    {
        if( (curr*11/10)>=curr_max)
        {
            if(++dly>=DIAG_OVER_CURR_DLY)
            {
                dly=DIAG_OVER_CURR_DLY;
                diag_sta.signal.over_curr=1;                
            }
        }
        else
        {
            dly=0;
            diag_sta.signal.over_curr=0;  
        }
    }
    
    return 1;
}


/*******************************************************************************
* Function Name  : diag_overload
* Description    : 过载检测
* Input          : 
* Output         : None
* Return         : None
1.超过元器件最大承载能力--暂定35A
*******************************************************************************/
static uint8_t diag_overload(void)
{
     int16_t curr=0;
    static uint16_t dly=0;
    
    //curr = meter.Curr;
    if(curr>DIAG_OVER_LOAD)
    {
        dly+=DIAG_FUN_CAL_INTER_TIME;
        if(dly>=DIAG_OVER_LOAD_DLY)
        {
            dly=DIAG_OVER_LOAD_DLY;
            diag_sta.signal.over_load=1;
        }
    }
    else
    {
        dly=0;
        diag_sta.signal.over_load=0;
    }
}

/*******************************************************************************
* Function Name  : diag_process
* Description    : 诊断任务主函数
* Input          : 
* Output         : None
* Return         : None
1.诊断任务调用周期100ms
*******************************************************************************/
void diag_process(void)
{
    diag_overcurr();
    diag_overload();
    diag_groud_wire();
}

